﻿/*
 Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved.
 For licensing, see LICENSE.html or http://ckeditor.com/license
 */

/**
 * @fileOverview Defines the {@link CKEDITOR.loader} objects, which is used to
 *        load core scripts and their dependencies from _source.
 */

if (typeof CKEDITOR == 'undefined')
    CKEDITOR = {};

if (!CKEDITOR.loader) {
    /**
     * Load core scripts and their dependencies from _source.
     * @namespace
     * @example
     */
    CKEDITOR.loader = (function () {
        // Table of script names and their dependencies.
        var scripts =
        {
            'core/_bootstrap': ['core/config', 'core/ckeditor', 'core/plugins', 'core/scriptloader', 'core/tools', /* The following are entries that we want to force loading at the end to avoid dependence recursion */ 'core/dom/comment', 'core/dom/elementpath', 'core/dom/text', 'core/dom/rangelist'],
            'core/ckeditor': ['core/ckeditor_basic', 'core/dom', 'core/dtd', 'core/dom/document', 'core/dom/element', 'core/editor', 'core/event', 'core/htmlparser', 'core/htmlparser/element', 'core/htmlparser/fragment', 'core/htmlparser/filter', 'core/htmlparser/basicwriter', 'core/tools'],
            'core/ckeditor_base': [],
            'core/ckeditor_basic': ['core/editor_basic', 'core/env', 'core/event'],
            'core/command': [],
            'core/config': ['core/ckeditor_base'],
            'core/dom': [],
            'core/dom/comment': ['core/dom/node'],
            'core/dom/document': ['core/dom', 'core/dom/domobject', 'core/dom/window'],
            'core/dom/documentfragment': ['core/dom/element'],
            'core/dom/element': ['core/dom', 'core/dom/document', 'core/dom/domobject', 'core/dom/node', 'core/dom/nodelist', 'core/tools'],
            'core/dom/elementpath': ['core/dom/element'],
            'core/dom/event': [],
            'core/dom/node': ['core/dom/domobject', 'core/tools'],
            'core/dom/nodelist': ['core/dom/node'],
            'core/dom/domobject': ['core/dom/event'],
            'core/dom/range': ['core/dom/document', 'core/dom/documentfragment', 'core/dom/element', 'core/dom/walker'],
            'core/dom/rangelist': ['core/dom/range'],
            'core/dom/text': ['core/dom/node', 'core/dom/domobject'],
            'core/dom/walker': ['core/dom/node'],
            'core/dom/window': ['core/dom/domobject'],
            'core/dtd': ['core/tools'],
            'core/editor': ['core/command', 'core/config', 'core/editor_basic', 'core/focusmanager', 'core/lang', 'core/plugins', 'core/skins', 'core/themes', 'core/tools', 'core/ui'],
            'core/editor_basic': ['core/event'],
            'core/env': [],
            'core/event': [],
            'core/focusmanager': [],
            'core/htmlparser': [],
            'core/htmlparser/comment': ['core/htmlparser'],
            'core/htmlparser/element': ['core/htmlparser', 'core/htmlparser/fragment'],
            'core/htmlparser/fragment': ['core/htmlparser', 'core/htmlparser/comment', 'core/htmlparser/text', 'core/htmlparser/cdata'],
            'core/htmlparser/text': ['core/htmlparser'],
            'core/htmlparser/cdata': ['core/htmlparser'],
            'core/htmlparser/filter': ['core/htmlparser'],
            'core/htmlparser/basicwriter': ['core/htmlparser'],
            'core/lang': [],
            'core/plugins': ['core/resourcemanager'],
            'core/resourcemanager': ['core/scriptloader', 'core/tools'],
            'core/scriptloader': ['core/dom/element', 'core/env'],
            'core/skins': ['core/scriptloader'],
            'core/themes': ['core/resourcemanager'],
            'core/tools': ['core/env'],
            'core/ui': []
        };

        var basePath = (function () {
            // This is a copy of CKEDITOR.basePath, but requires the script having
            // "_source/core/loader.js".
            if (CKEDITOR && CKEDITOR.basePath)
                return CKEDITOR.basePath;

            // Find out the editor directory path, based on its <script> tag.
            var path = '';
            var scripts = document.getElementsByTagName('script');

            for (var i = 0; i < scripts.length; i++) {
                var match = scripts[i].src.match(/(^|.*?[\\\/])(?:_source\/)?core\/loader.js(?:\?.*)?$/i);

                if (match) {
                    path = match[1];
                    break;
                }
            }

            // In IE (only) the script.src string is the raw valued entered in the
            // HTML. Other browsers return the full resolved URL instead.
            if (path.indexOf('://') == -1) {
                // Absolute path.
                if (path.indexOf('/') === 0)
                    path = location.href.match(/^.*?:\/\/[^\/]*/)[0] + path;
                // Relative path.
                else
                    path = location.href.match(/^[^\?]*\//)[0] + path;
            }

            return path;
        })();

        var timestamp = 'C6HH5UF';

        var getUrl = function (resource) {
            if (CKEDITOR && CKEDITOR.getUrl)
                return CKEDITOR.getUrl(resource);

            return basePath + resource +
                ( resource.indexOf('?') >= 0 ? '&' : '?' ) +
                't=' + timestamp;
        };

        var pendingLoad = [];

        /** @lends CKEDITOR.loader */
        return {
            /**
             * The list of loaded scripts in their loading order.
             * @type Array
             * @example
             * // Alert the loaded script names.
             * alert( <b>CKEDITOR.loader.loadedScripts</b> );
             */
            loadedScripts: [],

            loadPending: function () {
                var scriptName = pendingLoad.shift();

                if (!scriptName)
                    return;

                var scriptSrc = getUrl('_source/' + scriptName + '.js');

                var script = document.createElement('script');
                script.type = 'text/javascript';
                script.src = scriptSrc;

                function onScriptLoaded() {
                    // Append this script to the list of loaded scripts.
                    CKEDITOR.loader.loadedScripts.push(scriptName);

                    // Load the next.
                    CKEDITOR.loader.loadPending();
                }

                // We must guarantee the execution order of the scripts, so we
                // need to load them one by one. (#4145)
                // The following if/else block has been taken from the scriptloader core code.
                if (typeof(script.onreadystatechange) !== "undefined") {
                    /** @ignore */
                    script.onreadystatechange = function () {
                        if (script.readyState == 'loaded' || script.readyState == 'complete') {
                            script.onreadystatechange = null;
                            onScriptLoaded();
                        }
                    };
                }
                else {
                    /** @ignore */
                    script.onload = function () {
                        // Some browsers, such as Safari, may call the onLoad function
                        // immediately. Which will break the loading sequence. (#3661)
                        setTimeout(function () {
                            onScriptLoaded(scriptName);
                        }, 0);
                    };
                }

                document.body.appendChild(script);
            },

            /**
             * Loads a specific script, including its dependencies. This is not a
             * synchronous loading, which means that the code to be loaded will
             * not necessarily be available after this call.
             * @example
             * CKEDITOR.loader.load( 'core/dom/element' );
             */
            load: function (scriptName, defer) {
                // Check if the script has already been loaded.
                if (scriptName in this.loadedScripts)
                    return;

                // Get the script dependencies list.
                var dependencies = scripts[scriptName];
                if (!dependencies)
                    throw 'The script name"' + scriptName + '" is not defined.';

                // Mark the script as loaded, even before really loading it, to
                // avoid cross references recursion.
                this.loadedScripts[scriptName] = true;

                // Load all dependencies first.
                for (var i = 0; i < dependencies.length; i++)
                    this.load(dependencies[i], true);

                var scriptSrc = getUrl('_source/' + scriptName + '.js');

                // Append the <script> element to the DOM.
                // If the page is fully loaded, we can't use document.write
                // but if the script is run while the body is loading then it's safe to use it
                // Unfortunately, Firefox <3.6 doesn't support document.readyState, so it won't get this improvement
                if (document.body && (!document.readyState || document.readyState == 'complete')) {
                    pendingLoad.push(scriptName);

                    if (!defer)
                        this.loadPending();
                }
                else {
                    // Append this script to the list of loaded scripts.
                    this.loadedScripts.push(scriptName);

                    document.write('<script src="' + scriptSrc + '" type="text/javascript"><\/script>');
                }
            }
        };
    })();
}

// Check if any script has been defined for autoload.
if (CKEDITOR._autoLoad) {
    CKEDITOR.loader.load(CKEDITOR._autoLoad);
    delete CKEDITOR._autoLoad;
}
